/**
 * 性能数据收集器
 * 支持更多性能指标和智能分析
 */

import type { PerformanceMetrics } from '~/types/monitor';
import { ConfigManager } from './config-manager';

export class PerformanceCollector {
  private metrics: PerformanceMetrics = {};
  private observers: PerformanceObserver[] = [];
  private configManager: ConfigManager;
  private customMarks: Map<string, number> = new Map();
  private resourceMetrics: Map<string, any> = new Map();

  constructor() {
    this.configManager = ConfigManager.getInstance();

    if (
      process.client &&
      this.configManager.getConfig().enablePerformanceMonitor
    ) {
      this.initializeObservers();
      this.measureBasicMetrics();
      this.monitorResourceLoading();
      this.monitorMemoryUsage();
    }
  }

  /**
   * 初始化性能观察者
   */
  private initializeObservers(): void {
    if (!('PerformanceObserver' in window)) {
      console.warn('⚠️ [性能监控] PerformanceObserver 不支持，使用降级方案');
      this.fallbackMeasurement();
      return;
    }

    try {
      this.observePaintMetrics();
      this.observeLCPMetrics();
      this.observeFIDMetrics();
      this.observeCLSMetrics();
      this.observeNavigationMetrics();
      this.observeResourceMetrics();
    } catch (error) {
      console.warn('⚠️ [性能监控] 观察者初始化失败:', error);
      this.fallbackMeasurement();
    }
  }

  /**
   * 观察绘制指标
   */
  private observePaintMetrics(): void {
    const paintObserver = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        if (entry.name === 'first-contentful-paint') {
          this.metrics.FCP = Math.round(entry.startTime);
        } else if (entry.name === 'first-paint') {
          this.metrics.FP = Math.round(entry.startTime);
        }
      }
    });

    try {
      paintObserver.observe({ entryTypes: ['paint'] });
      this.observers.push(paintObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] Paint 指标观察失败:', error);
    }
  }

  /**
   * 观察LCP指标
   */
  private observeLCPMetrics(): void {
    const lcpObserver = new PerformanceObserver(list => {
      const entries = list.getEntries();
      if (entries.length > 0) {
        const lastEntry = entries[entries.length - 1];
        this.metrics.LCP = Math.round(lastEntry.startTime);
      }
    });

    try {
      lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
      this.observers.push(lcpObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] LCP 指标观察失败:', error);
    }
  }

  /**
   * 观察FID指标
   */
  private observeFIDMetrics(): void {
    const fidObserver = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        const fidValue = (entry as any).processingStart - entry.startTime;
        this.metrics.FID = Math.round(fidValue);
      }
    });

    try {
      fidObserver.observe({ entryTypes: ['first-input'] });
      this.observers.push(fidObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] FID 指标观察失败:', error);
    }
  }

  /**
   * 观察CLS指标
   */
  private observeCLSMetrics(): void {
    let clsValue = 0;
    let sessionValue = 0;
    let sessionEntries: any[] = [];

    const clsObserver = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        if (!(entry as any).hadRecentInput) {
          const firstSessionEntry = sessionEntries[0];
          const lastSessionEntry = sessionEntries[sessionEntries.length - 1];

          // 如果条目与上一条目的间隔小于1秒且与第一个条目的间隔小于5秒，则包含在当前会话中
          if (
            sessionValue &&
            entry.startTime - lastSessionEntry.startTime < 1000 &&
            entry.startTime - firstSessionEntry.startTime < 5000
          ) {
            sessionValue += (entry as any).value;
            sessionEntries.push(entry);
          } else {
            sessionValue = (entry as any).value;
            sessionEntries = [entry];
          }

          // 如果当前会话值大于当前CLS值，则更新CLS
          if (sessionValue > clsValue) {
            clsValue = sessionValue;
            this.metrics.CLS = Math.round(clsValue * 1000) / 1000;
          }
        }
      }
    });

    try {
      clsObserver.observe({ entryTypes: ['layout-shift'] });
      this.observers.push(clsObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] CLS 指标观察失败:', error);
    }
  }

  /**
   * 观察导航指标
   */
  private observeNavigationMetrics(): void {
    const navigationObserver = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        const navEntry = entry as PerformanceNavigationTiming;
        this.processNavigationTiming(navEntry);
      }
    });

    try {
      navigationObserver.observe({ entryTypes: ['navigation'] });
      this.observers.push(navigationObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] Navigation 指标观察失败:', error);
    }
  }

  /**
   * 观察资源指标
   */
  private observeResourceMetrics(): void {
    const resourceObserver = new PerformanceObserver(list => {
      for (const entry of list.getEntries()) {
        this.processResourceTiming(entry as PerformanceResourceTiming);
      }
    });

    try {
      resourceObserver.observe({ entryTypes: ['resource'] });
      this.observers.push(resourceObserver);
    } catch (error) {
      console.warn('⚠️ [性能监控] Resource 指标观察失败:', error);
    }
  }

  /**
   * 处理导航时序数据
   */
  private processNavigationTiming(entry: PerformanceNavigationTiming): void {
    this.metrics.TTFB = Math.round(entry.responseStart - entry.requestStart);
    this.metrics.pageLoadTime = Math.round(
      entry.loadEventEnd - entry.loadEventStart
    );
    this.metrics.redirectionTime = Math.round(
      entry.redirectEnd - entry.redirectStart
    );
    this.metrics.domainLookupTime = Math.round(
      entry.domainLookupEnd - entry.domainLookupStart
    );
    this.metrics.serverConnectionTime = Math.round(
      entry.connectEnd - entry.connectStart
    );
    this.metrics.serverResponseTime = Math.round(
      entry.responseEnd - entry.responseStart
    );
    this.metrics.documentInteractiveTime = Math.round(
      entry.domInteractive - entry.fetchStart
    );
    this.metrics.documentContentLoadedTime = Math.round(
      entry.domContentLoadedEventEnd - entry.fetchStart
    );
  }

  /**
   * 处理资源时序数据
   */
  private processResourceTiming(entry: PerformanceResourceTiming): void {
    const resourceType = this.getResourceType(entry.name);
    const size = entry.transferSize || entry.encodedBodySize || 0;
    const duration = entry.responseEnd - entry.startTime;

    if (!this.resourceMetrics.has(resourceType)) {
      this.resourceMetrics.set(resourceType, {
        count: 0,
        totalSize: 0,
        totalDuration: 0,
        maxDuration: 0,
      });
    }

    const metrics = this.resourceMetrics.get(resourceType);
    metrics.count++;
    metrics.totalSize += size;
    metrics.totalDuration += duration;
    metrics.maxDuration = Math.max(metrics.maxDuration, duration);

    // 更新总体指标
    this.metrics.resourceCount = (this.metrics.resourceCount || 0) + 1;
    this.metrics.bundleSize = (this.metrics.bundleSize || 0) + size;
  }

  /**
   * 获取资源类型
   */
  private getResourceType(url: string): string {
    if (url.includes('.js')) return 'script';
    if (url.includes('.css')) return 'stylesheet';
    if (url.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)) return 'image';
    if (url.match(/\.(woff|woff2|ttf|eot)$/i)) return 'font';
    if (url.includes('/api/') || url.includes('fetch')) return 'xhr';
    return 'other';
  }

  /**
   * 监控内存使用情况
   */
  private monitorMemoryUsage(): void {
    if ('memory' in performance) {
      const memory = (performance as any).memory;
      this.metrics.memoryUsage = {
        used: Math.round(memory.usedJSHeapSize / 1024 / 1024), // MB
        total: Math.round(memory.totalJSHeapSize / 1024 / 1024), // MB
        limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024), // MB
      };
    }
  }

  /**
   * 监控资源加载
   */
  private monitorResourceLoading(): void {
    // 监控长任务
    if ('PerformanceObserver' in window) {
      try {
        const longTaskObserver = new PerformanceObserver(list => {
          for (const entry of list.getEntries()) {
            if (entry.duration > 50) {
              // 长任务阈值50ms
              this.metrics.longTaskCount =
                (this.metrics.longTaskCount || 0) + 1;
              this.metrics.totalBlockingTime =
                (this.metrics.totalBlockingTime || 0) + (entry.duration - 50);
            }
          }
        });

        longTaskObserver.observe({ entryTypes: ['longtask'] });
        this.observers.push(longTaskObserver);
      } catch (error) {
        console.warn('⚠️ [性能监控] 长任务监控失败:', error);
      }
    }
  }

  /**
   * 降级测量方案
   */
  private fallbackMeasurement(): void {
    setTimeout(() => {
      if (window.performance) {
        // 使用旧版API获取基础指标
        this.measureBasicMetricsLegacy();
      }
    }, 1000);
  }

  /**
   * 测量基础性能指标
   */
  private measureBasicMetrics(): void {
    if (typeof window !== 'undefined' && window.performance) {
      // DOM加载完成时间
      if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', () => {
          this.metrics.domContentLoaded = Math.round(performance.now());
        });
      } else {
        this.metrics.domContentLoaded = Math.round(performance.now());
      }

      // 页面完全加载时间
      if (document.readyState === 'complete') {
        this.metrics.loadComplete = Math.round(performance.now());
        this.measureAdditionalMetrics();
      } else {
        window.addEventListener('load', () => {
          this.metrics.loadComplete = Math.round(performance.now());
          this.measureAdditionalMetrics();
        });
      }
    }
  }

  /**
   * 测量额外指标
   */
  private measureAdditionalMetrics(): void {
    // 测量内存使用
    this.monitorMemoryUsage();

    // 计算性能评分
    setTimeout(() => {
      this.calculatePerformanceScore();
    }, 2000);
  }

  /**
   * 使用旧版API测量基础指标
   */
  private measureBasicMetricsLegacy(): void {
    if (window.performance && window.performance.timing) {
      const timing = window.performance.timing;
      const navigationStart = timing.navigationStart;

      this.metrics.TTFB = timing.responseStart - timing.requestStart;
      this.metrics.pageLoadTime = timing.loadEventEnd - navigationStart;
      this.metrics.redirectionTime = timing.redirectEnd - timing.redirectStart;
      this.metrics.domainLookupTime =
        timing.domainLookupEnd - timing.domainLookupStart;
      this.metrics.serverConnectionTime =
        timing.connectEnd - timing.connectStart;
      this.metrics.serverResponseTime =
        timing.responseEnd - timing.responseStart;
      this.metrics.documentInteractiveTime =
        timing.domInteractive - navigationStart;
      this.metrics.documentContentLoadedTime =
        timing.domContentLoadedEventEnd - navigationStart;
    }
  }

  /**
   * 计算性能评分
   */
  private calculatePerformanceScore(): void {
    let score = 100;
    const weights = {
      FCP: 0.15,
      LCP: 0.25,
      FID: 0.25,
      CLS: 0.25,
      TTFB: 0.1,
    };

    // FCP评分 (0-2.5s: 100分, 2.5-4s: 50分, >4s: 0分)
    if (this.metrics.FCP) {
      if (this.metrics.FCP > 4000) score -= weights.FCP * 100;
      else if (this.metrics.FCP > 2500) score -= weights.FCP * 50;
    }

    // LCP评分 (0-2.5s: 100分, 2.5-4s: 50分, >4s: 0分)
    if (this.metrics.LCP) {
      if (this.metrics.LCP > 4000) score -= weights.LCP * 100;
      else if (this.metrics.LCP > 2500) score -= weights.LCP * 50;
    }

    // FID评分 (0-100ms: 100分, 100-300ms: 50分, >300ms: 0分)
    if (this.metrics.FID) {
      if (this.metrics.FID > 300) score -= weights.FID * 100;
      else if (this.metrics.FID > 100) score -= weights.FID * 50;
    }

    // CLS评分 (0-0.1: 100分, 0.1-0.25: 50分, >0.25: 0分)
    if (this.metrics.CLS) {
      if (this.metrics.CLS > 0.25) score -= weights.CLS * 100;
      else if (this.metrics.CLS > 0.1) score -= weights.CLS * 50;
    }

    // TTFB评分 (0-200ms: 100分, 200-500ms: 50分, >500ms: 0分)
    if (this.metrics.TTFB) {
      if (this.metrics.TTFB > 500) score -= weights.TTFB * 100;
      else if (this.metrics.TTFB > 200) score -= weights.TTFB * 50;
    }

    this.metrics.performanceScore = Math.max(0, Math.round(score));
  }

  /**
   * 获取当前性能指标
   */
  getMetrics(): PerformanceMetrics {
    return { ...this.metrics };
  }

  /**
   * 获取资源指标详情
   */
  getResourceMetrics(): Map<string, any> {
    return new Map(this.resourceMetrics);
  }

  /**
   * 测量自定义指标
   */
  mark(name: string): void {
    if (window.performance && window.performance.mark) {
      window.performance.mark(name);
      this.customMarks.set(name, performance.now());
    }
  }

  /**
   * 测量两个标记之间的时间
   */
  measure(name: string, startMark: string, endMark?: string): number {
    if (window.performance && window.performance.measure) {
      try {
        window.performance.measure(name, startMark, endMark);
        const measure = window.performance.getEntriesByName(name, 'measure')[0];
        return measure ? Math.round(measure.duration) : 0;
      } catch (error) {
        console.warn('⚠️ [性能监控] 测量失败:', error);

        // 降级方案：使用自定义标记计算
        const startTime = this.customMarks.get(startMark);
        const endTime = endMark
          ? this.customMarks.get(endMark)
          : performance.now();

        if (startTime && endTime) {
          return Math.round(endTime - startTime);
        }

        return 0;
      }
    }
    return 0;
  }

  /**
   * 获取性能建议
   */
  getPerformanceAdvice(): string[] {
    const advice: string[] = [];

    if (this.metrics.FCP && this.metrics.FCP > 3000) {
      advice.push('首次内容绘制时间过长，建议优化关键渲染路径');
    }

    if (this.metrics.LCP && this.metrics.LCP > 4000) {
      advice.push('最大内容绘制时间过长，建议优化图片和字体加载');
    }

    if (this.metrics.FID && this.metrics.FID > 100) {
      advice.push('首次输入延迟过长，建议减少主线程阻塞');
    }

    if (this.metrics.CLS && this.metrics.CLS > 0.1) {
      advice.push('累积布局偏移过大，建议为图片和广告预留空间');
    }

    if (this.metrics.bundleSize && this.metrics.bundleSize > 1024 * 1024) {
      advice.push('资源包过大，建议启用代码分割和懒加载');
    }

    if (this.metrics.longTaskCount && this.metrics.longTaskCount > 5) {
      advice.push('长任务过多，建议优化JavaScript执行');
    }

    return advice;
  }

  /**
   * 清理观察者
   */
  disconnect(): void {
    this.observers.forEach(observer => {
      try {
        observer.disconnect();
      } catch (error) {
        console.warn('⚠️ [性能监控] 观察者断开失败:', error);
      }
    });
    this.observers = [];
    this.customMarks.clear();
    this.resourceMetrics.clear();
  }
}
